package com.estudy.base.sucurity;

import com.alibaba.fastjson.util.IOUtils;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;

import static java.util.Base64.getDecoder;
import static java.util.Base64.getEncoder;

/**
 * 证书加密工具类
 * @author tim.xie
 * @date 2023/5/9 15:16
 */
@Slf4j
public class CipherUtil {

    /**
     * 获取crt证书公钥
     *
     * @param bytes
     * @return
     * @throws CertificateException
     * @throws IOException
     */
    public static PublicKey getPublicKeyFromCrt(byte[] bytes) throws CertificateException, IOException {
        ByteArrayInputStream fis = new ByteArrayInputStream(bytes);
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate oCert = (X509Certificate) cf.generateCertificate(fis);
            fis.close();
            PublicKey publicKey = oCert.getPublicKey();
            return publicKey;
        } finally {
            IOUtils.close(fis);
        }
    }


    /**
     * 获取crt证书私钥
     *
     * @param privateKeyFile
     * @return
     * @throws CertificateException
     * @throws IOException
     */
    public static PrivateKey getPrivateKeyFromCrt(File privateKeyFile) throws IOException, ClassNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException {
        PrivateKey privateKey = null;
        InputStream in = new FileInputStream(privateKeyFile);
        ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
        try {
            BigInteger m = (BigInteger) oin.readObject();
            BigInteger e = (BigInteger) oin.readObject();
            RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(m, e);
            KeyFactory fact = KeyFactory.getInstance("RSA");
            privateKey = fact.generatePrivate(privateKeySpec);
            oin.close();
        } finally {
            IOUtils.close(oin);
        }
        return privateKey;
    }

    /**
     * 根据crt证书公钥对数据进行加密
     *
     * @param rawData
     * @return
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    public static String encrypt(String rawData, byte[] fileBytes) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, CertificateException, IOException, UnrecoverableKeyException, KeyStoreException {
        PrivateKey privateKey = null;
        PublicKey publicKey = null;
        Cipher cipher;
        publicKey = getPublicKeyFromCrt(fileBytes);
        cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] bytes = cipher.doFinal(rawData.getBytes("UTF-8"));
        String strResult = getEncoder().encodeToString(bytes);
        return strResult;
    }

    /**
     * 根据crt证书公钥对数据进行解密
     *
     * @param rawData
     * @return
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    public static String decrypt(String rawData, byte[] fileBytes, File privateKeyFile) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, CertificateException, IOException, InvalidKeySpecException, ClassNotFoundException, UnrecoverableKeyException, KeyStoreException {
        PrivateKey privateKey = null;
        PublicKey publicKey = null;
        Cipher cipher;
        privateKey = getPrivateKeyFromCrt(privateKeyFile);
        cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] bytes = cipher.doFinal(getDecoder().decode(rawData));
        String strResult = new String(bytes, "UTF-8");
        return strResult;
    }

    public static void main(String[] args) {
        // crt证书地址
        String crtFile = "C:\\Users\\Tim\\Desktop\\fsdownload\\301000\\301000cert.crt";
        try {
            FileInputStream fis = new FileInputStream(crtFile);
            byte[] certs = new byte[fis.available()];
            fis.read(certs);
            fis.close();
            System.out.println(certs);
            // 加密的内容
            String bbb = "{\"nodeName\":\"浙江省电子政务外网安全监管普通\",\"registerIp\":\"10.17.241.67\",\"nodeCode\":\"330000\"}";
            String crtEnc = encrypt(bbb, certs);
            System.out.println("crt加密数据：" + crtEnc);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
